package be.nepherte.movmanager.client.gui.components;

import be.nepherte.movmanager.client.gui.MovManager;
import be.nepherte.movmanager.client.gui.InfoTab;
import be.nepherte.movmanager.client.gui.MoviesTab;
import be.nepherte.movmanager.client.gui.components.Tab.TabInfo;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * This class holds all the tabs of the GUI. It features methods for showing the
 * different tabs and built-in page history changes.
 * <p>
 * This file is part of MovManager.
 * </p>
 * <p>
 * MovManager is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * </p>
 * <p>
 * MovManager is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * MovManager. If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses</a>.
 * </p>
 * 
 * @author 	Bart Verhoeven, Google Inc.
 * @since 	20/05/2009
 * @version 0.1
 */
public class TabSink extends Composite implements ValueChangeHandler<String> {
	/**An image handler for the Tab Sink.*/
	private static final Tab.Images images = (Tab.Images) GWT.create(Tab.Images.class);
	/**A list with all the tabs attached to this sink.*/
	protected TabList list = new TabList(images);
	/**The info of the currently selected tab.*/
	private TabInfo curInfo;
	/**The currently selected tab.*/
	private Tab curTab;
	/**The HTML place holder for the tab description.*/
	private HTML description = new HTML();
	/**The panel that holds the tab list, description and everything else.*/
	private VerticalPanel panel = new VerticalPanel();
	
	/**
	 * When a previous history page is requested, show that page.
	 */
	public void onValueChange(ValueChangeEvent<String> event) {
		// Find the TabInfo associated with the history context. If one is
		// found, show it (It may not be found, for example, when the user 
		// mistypes a URL, or on startup, when the first context will be "").
		TabInfo info = list.find(event.getValue());
		
		if (info == null) {
			showInfo();
			return;
		}
		
		show(info, false);
	}

	/**
	 * Get the list with all the tabs .
	 * 
	 * @return	list
	 */
	public TabList getTabList() {
		return list;
	}

	/**
	 * Constructor for this object. Load all the tabs of the GUI and activate the Info tab.
	 */
	public TabSink() {
		// Load all the tabs.
		loadTabs();

		// Add everything to the panel and style/format it.
		panel.add(list);
		panel.add(description);
		panel.setWidth("100%");
		description.setStyleName("ks-Info");
		RootPanel.get().add(panel);
		
		// Add history support
		History.addValueChangeHandler(this);

		// Initialize the panel widget
		initWidget(panel);

		// Show the initial screen.
		if (History.getToken().length() > 0)
			History.fireCurrentHistoryState();
		else
			showInfo();
	}
	

	/**
	 * Show a tab.
	 * 
	 * @param	info
	 * 			the info of the tab you want to show.
	 * @param	affectHistory
	 * 			whether it should affect the browser history or not
	 */
	public void show(TabInfo info, boolean affectHistory) {
		// Don't bother re-displaying the existing tab. This can be an issue
		// in practice, because when the history context is set, our
		// onHistoryChanged() handler will attempt to show the currently-visible
		// sink.
		if (info == curInfo)
			return;
		
		curInfo = info;

		// Remove the old tab from the display area.
		if (curTab != null) {
			curTab.onHide();
			panel.remove(curTab);
		}

		// Get the new tab instance, and display its description in the tab list.
		curTab = info.getInstance();
		list.setTabSelection(info.getName());
		description.setHTML(info.getDescription());

		// Change the description background color.
		DOM.setStyleAttribute(description.getElement(), "backgroundColor", info.getColor());

		// Display the new tab.
		curTab.setVisible(false);
		panel.add(curTab);
		panel.setCellHorizontalAlignment(curTab, VerticalPanel.ALIGN_CENTER);
		curTab.setVisible(true);
		curTab.onShow();
	}

	/**
	 * Add all wanted tabs to the list. Note that this does not create actual instances
	 * of all tabs yet (they are created on-demand). This can make a significant
	 * difference in startup time.
	 */
	protected void loadTabs() {
		list.addTab(InfoTab.init());
		list.addTab(MoviesTab.init());
	}

	/**
	 * Show the info tab.
	 */
	private void showInfo() {
		show(list.find(MovManager.messages.infoTabName()), false);
	}
}
